#include "modbus_slave.h"

SlaveConfig slave = {0};

/**
 * @brief Modbus从机初始化函数.
 * @param 
 *   - *slave        从机结构体指针.
 *   - slave_addr    从机地址.
 *   - *port         端口配置结构体指针.
 *   - *callbacks    回调函数结构体指针.
 *   - frame_timeout 帧超时时间(ms).
 *
 * @return void
 */
void ModbusSlaveCreate(SlaveConfig *slave, uint8_t slave_addr,ModbusSlavePort *port,
                       SlaveCallBacks *callbacks, uint8_t frame_timeout) 
{
    memcpy(&slave->port, port, sizeof(ModbusSlavePort));
    memcpy(&slave->callbacks, callbacks, sizeof(SlaveCallBacks));
    slave->slave_addr = slave_addr;
    slave->rx_index = 0;
    slave->tx_length = 0;
    slave->last_rx_time = 0;
    slave->frame_timeout = frame_timeout; 
}

/**
 * @brief 处理接收到的Modbus请求.
 * @param 
 *   - *slave 从机结构体指针.
 *
 * @return void
 */
static void ProcessModbusRequest(SlaveConfig *slave) 
{   
    uint16_t reg_data[125] = {0};
    uint8_t function    = 0;
    uint8_t exception   = 0;
    uint16_t start_addr = 0;
    uint16_t reg_count  = 0;
    uint16_t i          = 0;
    uint16_t reg_addr   = 0;  
    uint16_t reg_value  = 0; 
    uint16_t crc        = 0;
    // 验证地址匹配
    if (slave->rx_buffer[0] != slave->slave_addr) return;
    
    // 验证CRC
    if (modbus_crc16(slave->rx_buffer, slave->rx_index) != 0) return;
    
    function    = slave->rx_buffer[1];
    exception   = MODBUS_EX_NONE;
    start_addr  = 0;
    reg_count   = 0;
    // 准备响应
    slave->tx_buffer[0] = slave->slave_addr;
    slave->tx_buffer[1] = function;
    slave->tx_length = 2;
    
    switch (function) {
        case 0x03: {  // 读保持寄存器
            start_addr = (slave->rx_buffer[2] << 8) | slave->rx_buffer[3];
            reg_count  = (slave->rx_buffer[4] << 8) | slave->rx_buffer[5];  
            
            // 验证寄存器数量
            if (reg_count < 1 || reg_count > 125) {
                exception = MODBUS_EX_ILLEGAL_VALUE;
                break;
            }
            
            // 调用用户回调读取寄存器           
            exception = slave->callbacks.read_holding_registers(start_addr, reg_count, reg_data);
            
            if (exception == MODBUS_EX_NONE) {
                slave->tx_buffer[2] = reg_count * 2;  // 字节数
                slave->tx_length = 3;
                
                // 填充寄存器数据
                for ( i = 0; i < reg_count; i++) {
                    slave->tx_buffer[slave->tx_length++] = (reg_data[i] >> 8) & 0xFF;
                    slave->tx_buffer[slave->tx_length++] = reg_data[i] & 0xFF;
                }
            }
            break;
        }       
        case 0x06: {  // 写单个寄存器
            reg_addr = (slave->rx_buffer[2] << 8) | slave->rx_buffer[3];
            reg_value = (slave->rx_buffer[4] << 8) | slave->rx_buffer[5];
            
            // 调用用户回调写入寄存器
            exception = slave->callbacks.write_single_register(reg_addr, reg_value);
            
            if (exception == MODBUS_EX_NONE) {
                // 直接返回原始数据作为响应
                memcpy(&slave->tx_buffer[2], &slave->rx_buffer[2], 4);
                slave->tx_length = 6;
            }
            break;
        }       
        default:  // 不支持的功能码
            exception = MODBUS_EX_ILLEGAL_FUNCTION;
            break;
    }    
    // 处理异常响应
    if (exception != MODBUS_EX_NONE) {
        slave->tx_buffer[1] |= 0x80;  // 设置异常标志
        slave->tx_buffer[2] = exception;
        slave->tx_length = 3;
    }   
    // 添加CRC
    crc = modbus_crc16(slave->tx_buffer, slave->tx_length);

    slave->tx_buffer[slave->tx_length++] = crc & 0xFF;
    slave->tx_buffer[slave->tx_length++] = (crc >> 8) & 0xFF;
    
    // 发送响应
    slave->port.uart_send(slave->tx_buffer, slave->tx_length);
    slave->tx_length = 0; // 新增：重置发送长度
}

/**
 * @brief Modbus从机轮询处理函数 (使用环形队列).
 * @param 
 *   - *slave     从机结构体指针.
 *   - *rx_queue  接收环形队列指针.
 *
 * @return void
 */
void ModbusSlaveProcess(SlaveConfig *slave, RingBuffer_t *rx_queue) 
{
    // 1. 获取当前时间戳
    uint32_t current_time = slave->port.get_timestamp_ms();     
    uint8_t temp_buf[64];
    uint16_t bytes_read = 0;
    uint8_t byte = 0;
    uint16_t i = 0;

    // 2. 检查接收缓冲区中是否有未处理的数据
    if (slave->rx_index > 0 && (current_time - slave->last_rx_time) > slave->frame_timeout) 
    {
        ProcessModbusRequest(slave);
        slave->rx_index = 0;
    }   
    
    // 3. 从环形队列中批量读取数据
    bytes_read = Queue_PopAll(rx_queue, temp_buf);
    // 4. 处理接收到的字节
    for (i = 0; i < bytes_read; i++) 
    {
        byte = temp_buf[i];       
        // 检查是否为新帧开始 (帧间隔超时)
        if (slave->rx_index > 0 && (current_time - slave->last_rx_time) > slave->frame_timeout) 
        {
            ProcessModbusRequest(slave);
            slave->rx_index = 0;  // 重置接收缓冲区
        }       
         // 6. 将新字节存入接收缓冲区
        if (slave->rx_index < sizeof(slave->rx_buffer)) 
        {
            slave->rx_buffer[slave->rx_index++] = byte;
            slave->last_rx_time = current_time;  // 更新最后接收时间
        } else {
            // 缓冲区溢出，重置
            slave->rx_index = 0;
        }
    }   
    // 4. 处理最后一帧 (无新数据时)
    if (slave->rx_index > 0 && (current_time - slave->last_rx_time) > slave->frame_timeout) 
    {
        ProcessModbusRequest(slave);
        slave->rx_index = 0;
    }
}